﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace Jemgine.Data
{
	public class MapData
	{
        public MapHeader Header = new MapHeader();

        public List<MapElement> Elements = new List<MapElement>();

        [ContentSerializerIgnore]
        public List<InputTerminal> Inputs = new List<InputTerminal>();

        [ContentSerializerIgnore]
        public List<ReferenceTarget> Targets = new List<ReferenceTarget>();

        public InputTerminal GetOutputTarget(OutputTerminal Terminal)
        {
            if (Terminal.TargetID == -1) return null;
            if (Terminal.TargetID >= Inputs.Count) return null;
            else return Inputs[Terminal.TargetID];
        }

        public ReferenceTarget GetReferenceTarget(ReferenceTerminal Terminal)
        {
            if (Terminal.TargetID == -1) return null;
            if (Terminal.TargetID >= Targets.Count) return null;

            else return Targets[Terminal.TargetID];
        }

        public ReferenceTarget GetAnchorTarget(Anchor Terminal)
        {
            if (Terminal.TargetID == -1) return null;
            else return Targets[Terminal.TargetID];
        }

        public MapData() { }

        public MapData(MapData CopyFrom)
        {
            foreach (MapElement Element in CopyFrom.Elements)
                Elements.Add(Element.Clone());
            Header = new MapHeader(CopyFrom.Header);
        }

        public void PostProcess(Engine.Simulation Sim, Vector2 PositionOffset,
            Action<Data.MapElement> ElementCallback)
        {
            EnumerateTargets();

            foreach (MapElement Element in Elements)
            {
                Element.PostProcess(PositionOffset, this, Sim);
                if (ElementCallback != null) ElementCallback(Element);
            }

            ClearInputs();
        }

        public void EnumerateTargets()
        {
            Inputs.Clear();
            Targets.Clear();
            foreach (MapElement Element in Elements)
                Element.EnumerateTargets(Inputs, Targets);
        }

        public void ClearInputs()
        {
            Inputs.Clear();
        }



        public void PreProcess()
        {
           PreProcess(Elements);
        }

        private void PreProcess(List<MapElement> Elements)
        {
            EnumerateTargets();
            int ID = 0;
            foreach (var Input in Inputs) { Input.ID = ID; ++ID; }
            ID = 0;
            foreach (var Target in Targets) { Target.ReferenceID = ID; ++ID; }

            foreach (MapElement Element in Elements)
                Element.PreProcess();
        }


        public void ClearAllIDs()
        {
            foreach (MapElement Element in Elements)
                Element.ClearAllIDs();
        }

        public MapData Export(List<int> Indicies)
        {
            ClearAllIDs();
            List<MapElement> ToCopy = new List<MapElement>();
            foreach (var Element in Indicies)
                ToCopy.Add(Elements[Element]);
            PreProcess(ToCopy);

            MapData tempMap = new MapData();
            tempMap.Elements = ToCopy;
            tempMap.Header = Header;
            MapData newMap = new MapData(tempMap);

            return newMap;
        }

        public void ForEachEntityElement(Predicate<EntityRecord> Filter, Action<EntityRecord, EntityElement> Callback)
        {
            foreach (var MapElement in Elements)
                if (MapElement is EntityRecord && Filter(MapElement as EntityRecord))
                    foreach (var Element in (MapElement as EntityRecord).AttachedElements)
                        Callback(MapElement as EntityRecord, Element);
        }

        public void ForEachMapElement(Predicate<MapElement> Filter, Action<MapElement> Callback)
        {
            foreach (var MapElement in Elements) if (Filter(MapElement)) Callback(MapElement);
        }
    }
}
